package com.chancein.cloud.report.charts.service.template;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chancein.cloud.ocr.process.domain.OcrExcelData;
import com.chancein.cloud.report.charts.domain.ChartJson;
import com.chancein.cloud.report.charts.domain.DataJson;
import com.chancein.cloud.report.charts.domain.OcrProcessReqDto;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;

import static com.chancein.cloud.report.charts.common.constant.CommonConstant.*;
import static com.chancein.cloud.report.charts.common.constant.OcrDataConstant.*;
import static com.chancein.cloud.report.charts.common.constant.EsConstant.*;
import static com.chancein.cloud.report.charts.config.InitParamConfig.*;
import static com.chancein.cloud.report.charts.service.ReportChartsService.ocrProcessApiService;

/**
 * 研报数据导出模板实现
 *
 * @author: LiaoZiHao
 * @date: 2023/8/2 18:30
 * Copyright © 2022 Hundsun Technologies Inc. All Rights Reserved
 */
@Slf4j
public class GenerateDataTemplate {
    /**
     * TODO 导出文件服务模板类
     *
     * @date 2023/8/2 19:15
     * @author liaozihao
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param fromSize  跳过的文档数量
     * @param pageSize  返回的文档数量
     */
    public static void exportData(String startTime, String endTime, Integer fromSize, Integer pageSize) throws IOException {
        log.info("report_charts_OCR[" + startTime + "to" + endTime + "].json导出[开始], from=[" + fromSize + "]");
        // 1. 封装一个 ES 请求
        SearchRequest searchRequest = GenerateDataTemplate.buildESReq(startTime, endTime);
        long totalHits = client.search(searchRequest).getHits().getTotalHits();
        StringBuilder sb = new StringBuilder();
        for (int from = fromSize; from < totalHits; from += pageSize) {
            // 2. 分页查数据
            searchRequest.source().from(from).size(pageSize);
            SearchResponse response = client.search(searchRequest);
            List<DataJson> dataJsonList = new ArrayList<>();
            // 3. 解析 ES 数据
            GenerateDataTemplate.parseEsData(response, dataJsonList);
            // 4. 发起 OCR 请求、解析 OCR 数据结果
            GenerateDataTemplate.launchAndParseOcrData(dataJsonList, sb);
            // 5. 异步写入文件
            StringBuilder finalSb = sb;
            Thread t = new Thread(() -> GenerateDataTemplate.createJsonFile(finalSb.toString(), "report_charts_OCR[" + startTime + "to" + endTime + "]"));
            t.start();
            sb = new StringBuilder();
        }
        log.info("report_charts_OCR[" + startTime + "to" + endTime + "].json文件导出[成功]");
    }
    /**
     * 封装一个 ES 请求
     *
     * @date 2023/8/2 19:00
     * @author liaozihao
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return {@link SearchRequest}
     */
    public static SearchRequest buildESReq(String startTime, String endTime) {
        // 1. 封装一个 ES 请求
        SearchRequest searchRequest = new SearchRequest("research_report_charts");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 1.1 时间过滤
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("pubDate")
                .gte(startTime)
                .lte(endTime);
        // 1.2 逻辑删除过滤
        TermQueryBuilder delFlagQueryBuilder = QueryBuilders.termQuery("delFlag", 0);
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .must(rangeQueryBuilder)
                .must(delFlagQueryBuilder);
        searchSourceBuilder.query(boolQueryBuilder);
        // 1.3 _score 字段剔除，为 null 后面会出问题
        String[] include = {"sourceId", "title_key", "rating", "delFlag", "title", "vectorgraphText", "picRect",
                "pdfFilePath", "sourceFileUrl", "@version", "id", "nlpCategory", "searchKeys",
                "org", "researchers", "created", "filePath", "dataFrom", "reportTitle", "updateTime",
                "pubDate", "labels", "createTime", "pageIndex", "analyst", "repeat_flag", "compared", "@timestamp"};
        String[] exclude = {"_score"};
        searchSourceBuilder.fetchSource(include, exclude);
        searchRequest.source(searchSourceBuilder);
        return searchRequest;
    }
    /**
     * 解析 ES 数据，封装一个 OCR 请求列表
     *
     * @date 2023/8/2 19:06
     * @author liaozihao
     * @param response     SearchResponse
     * @param dataJsonList 插入文件的一条数据（1. OCR 请求参数   2. esData）
     */
    public static void parseEsData(SearchResponse response, List<DataJson> dataJsonList) {
        SearchHits searchHits = response.getHits();
        SearchHit[] hits = searchHits.getHits();
        for (SearchHit hit: hits) {
            DataJson dataJson = new DataJson();
            JSONObject reportChartsJsonData = JSONObject.parseObject(hit.getSourceAsString());

            OcrProcessReqDto ocrProcessReqDto = new OcrProcessReqDto();
            ocrProcessReqDto.setOrigin(ServerUrl);
            String uri = reportChartsJsonData.getString("filePath");
            if (uri.charAt(0) != '/') {
                uri = "/" + uri;
                uri = "/report_chart/" + reportChartsJsonData.getString("pubDate").replace("-", "/") + uri;
            }
            ocrProcessReqDto.setUri(uri);
            ocrProcessReqDto.setVectorgraphText(reportChartsJsonData.getString("vectorgraphText"));
            // 封装一个请求所需的 chartJson 字段
            ChartJson chartJson = new ChartJson();
            chartJson.setId(reportChartsJsonData.getString("id"));
            chartJson.setPageIndex(reportChartsJsonData.getString("pageIndex"));
            chartJson.setPicRect(reportChartsJsonData.getString("picRect"));
            chartJson.setPdfFilePath(reportChartsJsonData.getString("pdfFilePath"));
            chartJson.setIpadMarkerType("搜索研报图表");
            ocrProcessReqDto.setChartJson(JSON.toJSONString(chartJson));
            ocrProcessReqDto.setTimestamp(1690350208642L);
            // 添加 OCR 请求参数
            dataJson.setOcrProcessReqDto(ocrProcessReqDto);
            // 添加 esData
            reportChartsJsonData.put("vectorgraphText", "null");
            dataJson.setEsData(reportChartsJsonData);

            dataJsonList.add(dataJson);
        }
    }
    /**
     * 发起OCR请求和解析OCR请求
     *
     * @date 2023/8/2 19:12
     * @author liaozihao
     * @param dataJsonList 写入文件的数据列表
     * @param sb           数据缓存区
     */
    public static void launchAndParseOcrData(List<DataJson> dataJsonList, StringBuilder sb) {
        for (DataJson dataJson: dataJsonList) {
            OcrExcelData ocrExcelData = ocrProcessApiService.getExcel(dataJson.getOcrProcessReqDto());

            String ocrParseData = (ocrExcelData != null) ? JSONObject.toJSONString(ocrExcelData) : OCR_RSP_UN_RESOLVE;
            JSONObject esData = dataJson.getEsData();
            esData.put(OCR_PARSE_DATA, ocrParseData);
            sb.append(esData).append(StrUtil.C_LF);
        }
    }
    /**
     * 创建 JSON 文件
     *
     * @date 2023/8/2 19:04
     * @author liaozihao
     * @param jsonString  json 字符串
     * @param fileName    文件名
     * @return {@link boolean}
     */
    public static boolean createJsonFile(String jsonString, String fileName) {
        // 标记文件生成是否成功
        boolean flag = true;
        // 拼接文件完整路径
        String fullPath = FILE_SAVE_PATH + File.separator + fileName + ".json";
        log.info("[写入一次文件] fullPath: " + fullPath);
        // 生成json格式文件
        try {
            // 保证创建一个新文件
            File file = new File(fullPath);
            if (!file.getParentFile().exists()) {
                // 如果父目录不存在，创建父目录
                if (! file.getParentFile().mkdirs()) {
                    return false;
                }
            }
            if (file.exists()) {
                // 如果已存在,往后追加文件内容
                FileWriter fileWriter = new FileWriter(file, true);
                fileWriter.write(jsonString);
                fileWriter.close();
            }
            if (!file.createNewFile()) {
                return false;
            }
            if(jsonString.contains("'")){
                //将单引号转义一下，因为JSON串中的字符串类型可以单引号引起来的
                jsonString = jsonString.replaceAll("'", "\\'");
            }
            if(jsonString.contains("\"")){
                //将双引号转义一下，因为JSON串中的字符串类型可以双引号引起来的
                jsonString = jsonString.replaceAll("\"", "\\\"");
            }
            // 将格式化后的字符串写入文件
            Writer write = new OutputStreamWriter(Files.newOutputStream(file.toPath()), StandardCharsets.UTF_8);
            write.write(jsonString);
            write.flush();
            write.close();
        } catch (Exception e) {
            flag = false;
            e.printStackTrace();
        }
        // 返回是否成功的标记
        return flag;
    }
}
